home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / graphics.c < prev    next >
C/C++ Source or Header  |  1993-09-15  |  56KB  |  2,040 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graphics.c%v 3.50.1.9 1993/08/05 05:38:59 woo Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graphics.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  *
  34.  * There is a mailing list for gnuplot users. Note, however, that the
  35.  * newsgroup 
  36.  *    comp.graphics.gnuplot 
  37.  * is identical to the mailing list (they
  38.  * both carry the same set of messages). We prefer that you read the
  39.  * messages through that newsgroup, to subscribing to the mailing list.
  40.  * (If you can read that newsgroup, and are already on the mailing list,
  41.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  42.  * removed from the mailing list.)
  43.  *
  44.  * The address for mailing to list members is
  45.  *       info-gnuplot@dartmouth.edu
  46.  * and for mailing administrative requests is 
  47.  *       info-gnuplot-request@dartmouth.edu
  48.  * The mailing list for bug reports is 
  49.  *       bug-gnuplot@dartmouth.edu
  50.  * The list of those interested in beta-test versions is
  51.  *       info-gnuplot-beta@dartmouth.edu
  52.  */
  53.  
  54. #include <stdio.h>
  55. #include <math.h>
  56. #include <assert.h>
  57. #if !defined(u3b2)
  58. #include <time.h>
  59. #endif
  60. #include "plot.h"
  61. #include "setshow.h"
  62.  
  63. #if defined(DJGPP)||defined(sun386)
  64. #define time_t unsigned long
  65. #endif
  66.  
  67. #ifndef AMIGA_SC_6_1
  68. extern char *strcpy(),*strncpy(),*strcat(),*ctime();
  69. #endif /* !AMIGA_SC_6_1 */
  70. char *tdate;
  71. #ifdef AMIGA_AC_5
  72. time_t dated;
  73. #else
  74. #if defined(apollo) || defined(sequent) || defined(u3b2) || defined(alliant) || defined(sun386)
  75. #include <sys/types.h> /* typedef long time_t; */
  76. #endif
  77. time_t dated; /* ,time(); */
  78. #include <time.h>
  79. #endif
  80.  
  81. void plot_impulses();
  82. void plot_lines();
  83. void plot_points();
  84. void plot_dots();
  85. void plot_bars();
  86. void plot_boxes();
  87. void edge_intersect();
  88. TBOOLEAN two_edge_intersect();
  89.  
  90. void plot_steps();            /* JG */
  91. void edge_intersect_steps();         /* JG */
  92. TBOOLEAN two_edge_intersect_steps();    /* JG */
  93.  
  94. /* for plotting error bars */
  95. #define ERRORBARTIC (t->h_tic/2) /* half the width of error bar tic mark */
  96.  
  97. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  98. #define max(a,b) ((a > b) ? a : b)
  99. #endif
  100.  
  101. #ifndef min
  102. #define min(a,b) ((a < b) ? a : b)
  103. #endif
  104.  
  105. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  106.  
  107. /* True if a and b have the same sign or zero (positive or negative) */
  108. #define samesign(a,b) ((a) * (b) >= 0)
  109.  
  110. /* Define the boundary of the plot
  111.  * These are computed at each call to do_plot, and are constant over
  112.  * the period of one do_plot. They actually only change when the term
  113.  * type changes and when the 'set size' factors change. 
  114.  */
  115. static int xleft, xright, ybot, ytop;
  116.  
  117. /* Boundary and scale factors, in user coordinates */
  118. /* x_min, x_max, y_min, y_max are local to this file and
  119.  * are not the same as variables of the same names in other files
  120.  */
  121. static double x_min, x_max, y_min, y_max;
  122. static double xscale, yscale;
  123.  
  124. /* And the functions to map from user to terminal coordinates */
  125. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  126. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  127.  
  128. /* (DFK) Watch for cancellation error near zero on axes labels */
  129. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  130. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  131. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  132.  
  133. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  134.  * macro, so I write it as a function on that machine.
  135.  */
  136. #ifndef sun386
  137. /* (DFK) Use 10^x if logscale is in effect, else x */
  138. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  139. #else
  140. static double
  141. CheckLog(is_log, base_log, x)
  142.      TBOOLEAN is_log;
  143.      double base_log;
  144.      double x;
  145. {
  146.   if (is_log)
  147.     return(pow(base_log, x));
  148.   else
  149.     return(x);
  150. }
  151. #endif /* sun386 */
  152.  
  153. double
  154. LogScale(coord, is_log, log_base_log, what, axis)
  155.     double coord;            /* the value */
  156.     TBOOLEAN is_log;            /* is this axis in logscale? */
  157.         double log_base_log;        /* if so, the log of its base */
  158.     char *what;            /* what is the coord for? */
  159.     char *axis;            /* which axis is this for ("x" or "y")? */
  160. {
  161.     if (is_log) {
  162.        if (coord <= 0.0) {
  163.           char errbuf[100];        /* place to write error message */
  164.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  165.                 what, axis, coord);
  166.           (*term_tbl[term].text)();
  167.           (void) fflush(outfile);
  168.           int_error(errbuf, NO_CARET);
  169.        } else
  170.         return(log(coord)/log_base_log);
  171.     }
  172.     return(coord);
  173. }
  174.  
  175. /* borders of plotting area */
  176. /* computed once on every call to do_plot */
  177. boundary(scaling)
  178.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  179. {
  180.     register struct termentry *t = &term_tbl[term];
  181.     /* luecken@udel.edu modifications 
  182.        sizes the plot according to the presence of labels, title,... */
  183.     if (strlen(ylabel) == 0)
  184.         xleft = (t->h_char)*8;
  185.     else
  186.         xleft = (t->h_char)*10;
  187.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  188.     if ((strlen(xlabel) != 0) || timedate)
  189.         if ((*t->text_angle)(1))
  190.             ybot = (t->v_char)*5/2 + 1;
  191.         else
  192.             ybot = (t->v_char)*7/2 + 1;    /* allow space for time at bottom */
  193.     else
  194.         ybot = (t->v_char)*3/2 + 1;
  195.     if ( (strlen(title) != 0) || timedate ||
  196.       ((strlen(ylabel) != 0) && ((*t->text_angle)(1) == FALSE)) )
  197.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  198.     else
  199.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)/2 - 1;
  200.     (void)(*t->text_angle)(0);
  201. }
  202.  
  203.  
  204. double dbl_raise(x,y)
  205. double x;
  206. int y;
  207. {
  208. register int i;
  209. double val;
  210.  
  211.     val = 1.0;
  212.     for (i=0; i < abs(y); i++)
  213.         val *= x;
  214.     if (y < 0 ) return (1.0/val);
  215.     return(val);
  216. }
  217.  
  218.  
  219. double make_tics(tmin,tmax,logscale,base_log)
  220. double tmin,tmax;
  221. TBOOLEAN logscale;
  222. double base_log;
  223. {
  224. register double xr,xnorm,tics,tic,l10;
  225.  
  226.     xr = fabs(tmin-tmax);
  227.     
  228.     l10 = log10(xr);
  229.     if (logscale) {
  230.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  231.         if (tic < 1.0)
  232.             tic = 1.0;
  233.     } else {
  234.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  235.         if (xnorm <= 2)
  236.             tics = 0.2;
  237.         else if (xnorm <= 5)
  238.             tics = 0.5;
  239.         else tics = 1.0;    
  240.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  241.     }
  242.     return(tic);
  243. }
  244.  
  245.  
  246. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  247. struct curve_points *plots;
  248. int pcount;            /* count of plots in linked list */
  249. double min_x, max_x;
  250. double min_y, max_y;
  251. {
  252. register struct termentry *t = &term_tbl[term];
  253. register int curve, xaxis_y, yaxis_x;
  254. register struct curve_points *this_plot;
  255. register double ytic, xtic;
  256. register int xl, yl;
  257.             /* only a Pyramid would have this many registers! */
  258. double xtemp, ytemp;
  259. struct text_label *this_label;
  260. struct arrow_def *this_arrow;
  261. TBOOLEAN scaling;
  262.  
  263.  
  264. /* store these in variables global to this file */
  265. /* otherwise, we have to pass them around a lot */
  266.      x_min = min_x;
  267.      x_max = max_x; 
  268.      y_min = min_y;
  269.      y_max = max_y;
  270.  
  271.     if (polar) {
  272.         /* will possibly change x_min, x_max, y_min, y_max */
  273.         polar_xform(plots,pcount);
  274.     }
  275.  
  276.     if (y_min == VERYLARGE || y_max == -VERYLARGE ||
  277.         x_min == VERYLARGE || x_max == -VERYLARGE)
  278.         int_error("all points undefined!", NO_CARET);
  279.  
  280. /*    Apply the desired viewport offsets. */
  281.      if (y_min < y_max) {
  282.         y_min -= boff;
  283.         y_max += toff;
  284.     } else {
  285.         y_max -= boff;
  286.         y_min += toff;
  287.     }
  288.      if (x_min < x_max) {
  289.         x_min -= loff;
  290.         x_max += roff;
  291.     } else {
  292.         x_max -= loff;
  293.         x_min += roff;
  294.     }
  295.  
  296. /* SETUP RANGES, SCALES AND TIC PLACES */
  297.     if (ytics && yticdef.type == TIC_COMPUTED) {
  298.        ytic = make_tics(y_min,y_max,is_log_y,base_log_y);
  299.     
  300.        if (autoscale_ly) {
  301.           if (y_min < y_max) {
  302.              y_min = ytic * floor(y_min/ytic);       
  303.              y_max = ytic * ceil(y_max/ytic);
  304.           }
  305.           else {            /* reverse axis */
  306.              y_min = ytic * ceil(y_min/ytic);       
  307.              y_max = ytic * floor(y_max/ytic);
  308.           }
  309.        }
  310.     }
  311.  
  312.     if (xtics && xticdef.type == TIC_COMPUTED) {
  313.        xtic = make_tics(x_min,x_max,is_log_x,base_log_x);
  314.        
  315.        if (autoscale_lx) {
  316.           if (x_min < x_max) {
  317.              x_min = xtic * floor(x_min/xtic);    
  318.              x_max = xtic * ceil(x_max/xtic);
  319.           } else {
  320.              x_min = xtic * ceil(x_min/xtic);
  321.              x_max = xtic * floor(x_max/xtic);    
  322.           }
  323.        }
  324.     }
  325.  
  326. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  327.     if (fabs(x_max - x_min) < zero)
  328.         int_error("x_min should not equal x_max!",NO_CARET);
  329.     if (fabs(y_max - y_min) < zero)
  330.         int_error("y_min should not equal y_max!",NO_CARET);
  331.  
  332. /* INITIALIZE TERMINAL */
  333.     if (!term_init) {
  334.         (*t->init)();
  335.         term_init = TRUE;
  336.     }
  337.     screen_ok = FALSE;
  338.     scaling = (*t->scale)(xsize, ysize);
  339.     (*t->graphics)();
  340.  
  341.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  342.      boundary(scaling);
  343.  
  344. /* SCALE FACTORS */
  345.     yscale = (ytop - ybot)/(y_max - y_min);
  346.     xscale = (xright - xleft)/(x_max - x_min);
  347.     
  348. /* DRAW AXES */
  349.     (*t->linetype)(-1);    /* axis line type */
  350.     xaxis_y = map_y(0.0);
  351.     yaxis_x = map_x(0.0); 
  352.  
  353.     if (xaxis_y < ybot)
  354.         xaxis_y = ybot;                /* save for impulse plotting */
  355.     else if (xaxis_y >= ytop)
  356.         xaxis_y = ytop ;
  357.     else if (xzeroaxis && !is_log_y) {
  358.         (*t->move)(xleft,xaxis_y);
  359.         (*t->vector)(xright,xaxis_y);
  360.     } else if (is_log_y){
  361.         xaxis_y = ybot;
  362.     }
  363.  
  364.     if (yzeroaxis && !is_log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  365.         (*t->move)(yaxis_x,ybot);
  366.         (*t->vector)(yaxis_x,ytop);
  367.     }
  368.  
  369. /* DRAW TICS */
  370.     (*t->linetype)(-2); /* border linetype */
  371.  
  372.     /* label y axis tics */
  373.      if (ytics) {
  374.         switch (yticdef.type) {
  375.            case TIC_COMPUTED: {
  376.                if (y_min < y_max)
  377.                 draw_ytics(ytic * floor(y_min/ytic),
  378.                         ytic,
  379.                         ytic * ceil(y_max/ytic));
  380.               else
  381.                 draw_ytics(ytic * floor(y_max/ytic),
  382.                         ytic,
  383.                         ytic * ceil(y_min/ytic));
  384.  
  385.               break;
  386.            }
  387.             case TIC_MONTH:{
  388.             draw_month_ytics();
  389.             break;
  390.             }
  391.             case TIC_DAY: {
  392.             draw_day_ytics();
  393.             break;
  394.             }
  395.            case TIC_SERIES: {
  396.               draw_series_ytics(yticdef.def.series.start, 
  397.                             yticdef.def.series.incr, 
  398.                             yticdef.def.series.end);
  399.               break;
  400.            }
  401.            case TIC_USER: {
  402.               draw_set_ytics(yticdef.def.user);
  403.               break;
  404.            }
  405.            default: {
  406.               (*t->text)();
  407.                 (void) fflush(outfile);
  408.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  409.               break;        /* NOTREACHED */
  410.            }
  411.         }
  412.     }
  413.  
  414.     /* label x axis tics */
  415.      if (xtics) {
  416.         switch (xticdef.type) {
  417.            case TIC_COMPUTED: {
  418.                if (x_min < x_max)
  419.                 draw_xtics(xtic * floor(x_min/xtic),
  420.                         xtic,
  421.                         xtic * ceil(x_max/xtic));
  422.               else
  423.                 draw_xtics(xtic * floor(x_max/xtic),
  424.                         xtic,
  425.                         xtic * ceil(x_min/xtic));
  426.  
  427.               break;
  428.            }
  429.             case TIC_MONTH: {
  430.             draw_month_xtics();
  431.             break;
  432.             }
  433.             case TIC_DAY : {
  434.             draw_day_xtics();
  435.             break;
  436.             }
  437.            case TIC_SERIES: {
  438.               draw_series_xtics(xticdef.def.series.start, 
  439.                             xticdef.def.series.incr, 
  440.                             xticdef.def.series.end);
  441.               break;
  442.            }
  443.            case TIC_USER: {
  444.               draw_set_xtics(xticdef.def.user);
  445.               break;
  446.            }
  447.            default: {
  448.               (*t->text)();
  449.               (void) fflush(outfile);
  450.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  451.               break;        /* NOTREACHED */
  452.            }
  453.         }
  454.     }
  455.  
  456. /* DRAW PLOT BORDER */
  457.     (*t->linetype)(-2); /* border linetype */
  458.     if (draw_border) {
  459.         (*t->move)(xleft,ybot);
  460.         (*t->vector)(xright,ybot);
  461.         (*t->vector)(xright,ytop);
  462.         (*t->vector)(xleft,ytop);
  463.         (*t->vector)(xleft,ybot);
  464.     }
  465.  
  466. /* PLACE YLABEL */
  467.     if (strlen(ylabel) > 0) {
  468.         int x, y;
  469.  
  470.         x = ylabel_xoffset * t->h_char;
  471.         y = ylabel_yoffset * t->v_char;
  472.         if ((*t->text_angle)(1)) {
  473.             if ((*t->justify_text)(CENTRE)) {
  474.                 (*t->put_text)(x+(t->v_char),
  475.                          y+(ytop+ybot)/2, ylabel);
  476.             }
  477.             else {
  478.                 (*t->put_text)(x+(t->v_char),
  479.                            y+(ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  480.                          ylabel);
  481.             }
  482.         }
  483.         else {
  484.             (void)(*t->justify_text)(LEFT);
  485.             (*t->put_text)(x,y+ytop+(t->v_char), ylabel);
  486.         }
  487.         (void)(*t->text_angle)(0);
  488.     }
  489.  
  490. /* PLACE XLABEL */
  491.     if (strlen(xlabel) > 0) {
  492.         int x, y;
  493.  
  494.         x = xlabel_xoffset * t->h_char;
  495.         y = xlabel_yoffset * t->v_char;
  496.  
  497.             if ((*t->justify_text)(CENTRE)) 
  498.             (*t->put_text)(x+(xleft+xright)/2,
  499.                        y+ybot-2*(t->v_char), xlabel);
  500.             else
  501.             (*t->put_text)(x+(xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  502.                            y+ybot-2*(t->v_char), xlabel);
  503.     }
  504.  
  505. /* PLACE TITLE */
  506.     if (strlen(title) > 0) {
  507.         int x, y;
  508.  
  509.         x = title_xoffset * t->h_char;
  510.         y = title_yoffset * t->v_char;
  511.  
  512.             if ((*t->justify_text)(CENTRE))
  513.             (*t->put_text)(x+(xleft+xright)/2,
  514.                        y+ytop+(t->v_char), title);
  515.             else
  516.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  517.                        y+ytop+(t->v_char), title);
  518.     }
  519.  
  520.  
  521. /* PLACE TIMEDATE */
  522.     if (timedate) {
  523.         int x, y;
  524.  
  525.         x = time_xoffset * t->h_char;
  526.         y = time_yoffset * t->v_char;
  527.         dated = time( (time_t *) 0);
  528.         tdate = ctime( &dated);
  529.         tdate[24]='\0';
  530.         (void)(*t->justify_text)(LEFT);
  531.         if ((*t->text_angle)(1)) {
  532.             (void)(*t->text_angle)(0);
  533.             (*t->put_text)(x, y+ytop+(t->v_char), tdate);
  534.         }
  535.         else {
  536.             (void)(*t->text_angle)(0);
  537.             (*t->put_text)(x,
  538.                          y+ybot-3*(t->v_char), tdate);
  539.         }
  540.     }
  541.  
  542. /* PLACE LABELS */
  543.     for (this_label = first_label; this_label!=NULL;
  544.             this_label=this_label->next ) {
  545.          xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  546.          ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  547.         if ((*t->justify_text)(this_label->pos)) {
  548.             (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  549.         }
  550.         else {
  551.             switch(this_label->pos) {
  552.                 case  LEFT:
  553.                     (*t->put_text)(map_x(xtemp),map_y(ytemp),
  554.                         this_label->text);
  555.                     break;
  556.                 case CENTRE:
  557.                     (*t->put_text)(map_x(xtemp)-
  558.                         (t->h_char)*strlen(this_label->text)/2,
  559.                         map_y(ytemp), this_label->text);
  560.                     break;
  561.                 case RIGHT:
  562.                     (*t->put_text)(map_x(xtemp)-
  563.                         (t->h_char)*strlen(this_label->text),
  564.                         map_y(ytemp), this_label->text);
  565.                     break;
  566.             }
  567.          }
  568.      }
  569.  
  570. /* PLACE ARROWS */
  571.     (*t->linetype)(0);    /* arrow line type */
  572.     for (this_arrow = first_arrow; this_arrow!=NULL;
  573.         this_arrow = this_arrow->next ) {
  574.        int sx = map_x(LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x"));
  575.        int sy = map_y(LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y"));
  576.        int ex = map_x(LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x"));
  577.        int ey = map_y(LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y"));
  578.        
  579.        (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  580.     }
  581.  
  582.  
  583. /* DRAW CURVES */
  584.     if (key == -1) {
  585.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  586.         yl = ytop - (t->v_tic) - (t->v_char);
  587.     }
  588.     if (key == 1) {
  589.         xl = map_x( LogScale(key_x, is_log_x, log_base_log_x, "key", "x") );
  590.         yl = map_y( LogScale(key_y, is_log_y, log_base_log_y, "key", "y") );
  591.     }
  592.  
  593.     this_plot = plots;
  594.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  595.         int oldkey = key;
  596.  
  597.         (*t->linetype)(this_plot->line_type);
  598.  
  599.         if (this_plot->title && !*this_plot->title) {
  600.             key = 0;
  601.         } else {
  602.         if (key != 0 && this_plot->title) {
  603.             if ((*t->justify_text)(RIGHT)) {
  604.                 (*t->put_text)(xl,
  605.                     yl,this_plot->title);
  606.             }
  607.             else {
  608.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  609.                          xleft, xright))
  610.                  (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  611.                              yl,this_plot->title);
  612.             }
  613.         }
  614.         }
  615.  
  616.         switch(this_plot->plot_style) {
  617.             case IMPULSES: {
  618.                if (key != 0 && this_plot->title) {
  619.                   (*t->move)(xl+(t->h_char),yl);
  620.                   (*t->vector)(xl+4*(t->h_char),yl);
  621.                }
  622.                plot_impulses(this_plot, yaxis_x, xaxis_y);
  623.                break;
  624.             }
  625.             case LINES: {
  626.                if (key != 0 && this_plot->title) {
  627.                   (*t->move)(xl+(int)(t->h_char),yl);
  628.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  629.                }
  630.                plot_lines(this_plot);
  631.                break;
  632.             }
  633. /* JG */        case STEPS: {
  634.                if (key != 0 && this_plot->title) {
  635.                   (*t->move)(xl+(int)(t->h_char),yl);
  636.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  637.                }
  638.                plot_steps(this_plot);
  639.                break;
  640.             }
  641.             case POINTSTYLE: {
  642.                if (key != 0 && this_plot->title) {
  643.                   (*t->point)(xl+2*(t->h_char),yl,
  644.                             this_plot->point_type);
  645.                }
  646.                plot_points(this_plot);
  647.                break;
  648.             }
  649.             case LINESPOINTS: {
  650.                /* put lines */
  651.                if (key != 0 && this_plot->title) {
  652.                   (*t->move)(xl+(t->h_char),yl);
  653.                   (*t->vector)(xl+4*(t->h_char),yl);
  654.                }
  655.                plot_lines(this_plot);
  656.  
  657.                /* put points */
  658.                if (key != 0 && this_plot->title) {
  659.                   (*t->point)(xl+2*(t->h_char),yl,
  660.                             this_plot->point_type);
  661.                }
  662.                plot_points(this_plot);
  663.                break;
  664.             }
  665.             case DOTS: {
  666.                if (key != 0 && this_plot->title) {
  667.                   (*t->point)(xl+2*(t->h_char),yl, -1);
  668.                }
  669.                plot_dots(this_plot);
  670.                break;
  671.             }
  672.             case ERRORBARS: {
  673.                if (key != 0 && this_plot->title) {
  674.                   (*t->point)(xl+2*(t->h_char),yl,
  675.                             this_plot->point_type);
  676.                }
  677.                plot_points(this_plot);
  678.  
  679.                /* for functions, just like POINTSTYLE */
  680.                if (this_plot->plot_type == DATA) {
  681.                   if (key != 0 && this_plot->title) {
  682.                      (*t->move)(xl+(t->h_char),yl);
  683.                      (*t->vector)(xl+4*(t->h_char),yl);
  684.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  685.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  686.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  687.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  688.                   }
  689.                   plot_bars(this_plot);
  690.                }
  691.                break;
  692.             }
  693.             case BOXERROR: {
  694.                if (this_plot->plot_type == DATA) {
  695.                   if (key != 0 && this_plot->title) {
  696.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  697.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  698.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  699.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  700.                   }
  701.                   plot_bars(this_plot);
  702.                }
  703.             }
  704.             /* no break */
  705.             case BOXES: {
  706.                if (key != 0 && this_plot->title) {
  707.                   (*t->move)(xl+(t->h_char),yl);
  708.                   (*t->vector)(xl+4*(t->h_char),yl);
  709.                }
  710.                plot_boxes(this_plot,xaxis_y);
  711.                break;
  712.             }
  713.  
  714.         }
  715.         if (key && this_plot->title) {
  716.             yl = yl - (t->v_char);
  717.         }
  718.         key = oldkey;
  719.     }
  720.     (*t->text)();
  721.     (void) fflush(outfile);
  722. }
  723.  
  724. /* plot_impulses:
  725.  * Plot the curves in IMPULSES style
  726.  */
  727. void
  728. plot_impulses(plot, yaxis_x, xaxis_y)
  729.     struct curve_points *plot;
  730.     int yaxis_x, xaxis_y;
  731. {
  732.     int i;
  733.     int x,y;
  734.     struct termentry *t = &term_tbl[term];
  735.  
  736.     for (i = 0; i < plot->p_count; i++) {
  737.        switch (plot->points[i].type) {
  738.           case INRANGE: {
  739.              x = map_x(plot->points[i].x);
  740.              y = map_y(plot->points[i].y);
  741.              break;
  742.           }
  743.           case OUTRANGE: {
  744.              if (!inrange(plot->points[i].x, x_min,x_max))
  745.                continue;
  746.              x = map_x(plot->points[i].x);
  747.              if ((y_min < y_max 
  748.                  && plot->points[i].y < y_min)
  749.                 || (y_max < y_min 
  750.                     && plot->points[i].y > y_min))
  751.                y = map_y(y_min);
  752.              if ((y_min < y_max 
  753.                  && plot->points[i].y > y_max)
  754.                 || (y_max<y_min 
  755.                     && plot->points[i].y < y_max))
  756.                y = map_y(y_max);
  757.              break;
  758.           }
  759.           default:        /* just a safety */
  760.           case UNDEFINED: {
  761.              continue;
  762.           }
  763.        }
  764.                     
  765.        if (polar)
  766.           (*t->move)(yaxis_x,xaxis_y);
  767.        else
  768.           (*t->move)(x,xaxis_y);
  769.        (*t->vector)(x,y);
  770.     }
  771.  
  772. }
  773.  
  774. /* plot_lines:
  775.  * Plot the curves in LINES style
  776.  */
  777. void
  778. plot_lines(plot)
  779.     struct curve_points *plot;
  780. {
  781.     int i;                /* point index */
  782.     int x,y;                /* point in terminal coordinates */
  783.     struct termentry *t = &term_tbl[term];
  784.     enum coord_type prev = UNDEFINED; /* type of previous point */
  785.     double ex, ey;            /* an edge point */
  786.     double lx[2], ly[2];        /* two edge points */
  787.  
  788.     for (i = 0; i < plot->p_count; i++) {
  789.        switch (plot->points[i].type) {
  790.           case INRANGE: {
  791.              x = map_x(plot->points[i].x);
  792.              y = map_y(plot->points[i].y);
  793.  
  794.              if (prev == INRANGE) {
  795.                 (*t->vector)(x,y);
  796.              } else if (prev == OUTRANGE) {
  797.                 /* from outrange to inrange */
  798.                 if (!clip_lines1) {
  799.                     (*t->move)(x,y);
  800.                 } else {
  801.                     edge_intersect(plot->points, i, &ex, &ey);
  802.                     (*t->move)(map_x(ex), map_y(ey));
  803.                     (*t->vector)(x,y);
  804.                 }
  805.              } else {        /* prev == UNDEFINED */
  806.                 (*t->move)(x,y);
  807.                 (*t->vector)(x,y);
  808.              }
  809.                     
  810.              break;
  811.           }
  812.           case OUTRANGE: {
  813.              if (prev == INRANGE) {
  814.                 /* from inrange to outrange */
  815.                 if (clip_lines1) {
  816.                     edge_intersect(plot->points, i, &ex, &ey);
  817.                     (*t->vector)(map_x(ex), map_y(ey));
  818.                 }
  819.              } else if (prev == OUTRANGE) {
  820.                 /* from outrange to outrange */
  821.                 if (clip_lines2) {
  822.                     if (two_edge_intersect(plot->points, i, lx, ly)) {
  823.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  824.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  825.                     }
  826.                 }
  827.              }
  828.              break;
  829.           }
  830.           default:        /* just a safety */
  831.           case UNDEFINED: {
  832.              break;
  833.           }
  834.        }
  835.        prev = plot->points[i].type;
  836.     }
  837. }
  838.  
  839. /* XXX - JG  */
  840. /* plot_steps:                
  841.  * Plot the curves in STEPS style
  842.  */
  843. void
  844. plot_steps(plot)
  845. struct curve_points *plot;
  846. {
  847.     int i;                /* point index */
  848.     int x,y;                /* point in terminal coordinates */
  849.     struct termentry *t = &term_tbl[term];
  850.     enum coord_type prev = UNDEFINED;    /* type of previous point */
  851.     double ex, ey;            /* an edge point */
  852.     double lx[2], ly[2];        /* two edge points */
  853.     int xprev, yprev;            /* previous point coordinates */
  854.  
  855.     for (i = 0; i < plot->p_count; i++) {
  856.        switch (plot->points[i].type) {
  857.           case INRANGE: {
  858.              x = map_x(plot->points[i].x);
  859.              y = map_y(plot->points[i].y);
  860.  
  861.              if (prev == INRANGE) {
  862.                 (*t->vector)(x,yprev);
  863.                 (*t->vector)(x,y);
  864.              } else if (prev == OUTRANGE) {
  865.                 /* from outrange to inrange */
  866.                 if (!clip_lines1) {
  867.                     (*t->move)(x,y);
  868.                 } else {        /* find edge intersection */
  869.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  870.                     (*t->move)(map_x(ex), map_y(ey));
  871.                     (*t->vector)(x,map_y(ey));
  872.                     (*t->vector)(x,y);
  873.                 }
  874.              } else {        /* prev == UNDEFINED */
  875.                 (*t->move)(x,y);
  876.                 (*t->vector)(x,y);
  877.              }
  878.              break;
  879.           }
  880.           case OUTRANGE: {
  881.              if (prev == INRANGE) {
  882.                 /* from inrange to outrange */
  883.                 if (clip_lines1) {
  884.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  885.                     (*t->vector)(map_x(ex), yprev);
  886.                     (*t->vector)(map_x(ex), map_y(ey));
  887.                 }
  888.              } else if (prev == OUTRANGE) {
  889.                 /* from outrange to outrange */
  890.                 if (clip_lines2) {
  891.                     if (two_edge_intersect_steps(plot->points, i, lx, ly)) {
  892.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  893.                        (*t->vector)(map_x(lx[1]), map_y(ly[0]));
  894.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  895.                     }
  896.                 }
  897.              }
  898.              break;
  899.           }
  900.           default:        /* just a safety */
  901.           case UNDEFINED: {
  902.              break;
  903.           }
  904.        }
  905.        prev  = plot->points[i].type;
  906.        xprev = x;
  907.        yprev = y;
  908.     }
  909. }
  910.  
  911. /* plot_bars:
  912.  * Plot the curves in ERRORBARS style
  913.  *  we just plot the bars; the points are plotted in plot_points
  914.  */
  915. void
  916. plot_bars(plot)
  917.     struct curve_points *plot;
  918. {
  919.     int i;                /* point index */
  920.     struct termentry *t = &term_tbl[term];
  921.     double x;                /* position of the bar */
  922.     double ylow, yhigh;        /* the ends of the bars */
  923.     unsigned int xM, ylowM, yhighM; /* the mapped version of above */
  924.     TBOOLEAN low_inrange, high_inrange;
  925.     int tic = ERRORBARTIC;
  926.     
  927.     for (i = 0; i < plot->p_count; i++) {
  928.        /* undefined points don't count */
  929.        if (plot->points[i].type == UNDEFINED)
  930.         continue;
  931.  
  932.        /* check to see if in xrange */
  933.        x = plot->points[i].x;
  934.        if (! inrange(x, x_min, x_max))
  935.         continue;
  936.        xM = map_x(x);
  937.  
  938.        /* find low and high points of bar, and check yrange */
  939.        yhigh = plot->points[i].yhigh;
  940.        ylow = plot->points[i].ylow;
  941.  
  942.        high_inrange = inrange(yhigh, y_min,y_max);
  943.        low_inrange = inrange(ylow, y_min,y_max);
  944.  
  945.        /* compute the plot position of yhigh */
  946.        if (high_inrange)
  947.         yhighM = map_y(yhigh);
  948.        else if (samesign(yhigh-y_max, y_max-y_min))
  949.         yhighM = map_y(y_max);
  950.        else
  951.         yhighM = map_y(y_min);
  952.        
  953.        /* compute the plot position of ylow */
  954.        if (low_inrange)
  955.         ylowM = map_y(ylow);
  956.        else if (samesign(ylow-y_max, y_max-y_min))
  957.         ylowM = map_y(y_max);
  958.        else
  959.         ylowM = map_y(y_min);
  960.  
  961.        if (!high_inrange && !low_inrange && ylowM == yhighM)
  962.         /* both out of range on the same side */
  963.           continue;
  964.  
  965.        /* by here everything has been mapped */
  966.        (*t->move)(xM, ylowM);
  967.        (*t->vector)(xM, yhighM); /* draw the main bar */
  968.        (*t->move)(xM-tic, ylowM); /* draw the bottom tic */
  969.        (*t->vector)(xM+tic, ylowM);
  970.        (*t->move)(xM-tic, yhighM); /* draw the top tic */
  971.        (*t->vector)(xM+tic, yhighM);
  972.     }
  973. }
  974.  
  975. /* plot_boxes:
  976.  * Plot the curves in BOXES style
  977.  */
  978. void
  979. plot_boxes(plot,xaxis_y)
  980.     struct curve_points *plot;
  981.     int xaxis_y;
  982. {
  983.     int i;                /* point index */
  984.     int xl,xr,yt;            /* point in terminal coordinates */
  985.     double dxl,dxr,dyt;
  986.     struct termentry *t = &term_tbl[term];
  987.     enum coord_type prev = UNDEFINED; /* type of previous point */
  988.  
  989.     for (i = 0; i < plot->p_count; i++) {
  990.        switch (plot->points[i].type) {
  991.           case OUTRANGE:
  992.           case INRANGE: {
  993.             if (plot->points[i].z<0.0) {
  994.                if (boxwidth<0.0) {
  995.                     /* calculate width */
  996.                     if (prev!=UNDEFINED)
  997.                         dxl = (plot->points[i-1].x - plot->points[i].x)/2.0;
  998.                     else
  999.                         dxl = 0.0;
  1000.                     if (i < plot->p_count-1) {
  1001.                         if (plot->points[i+1].type!=UNDEFINED)
  1002.                             dxr = (plot->points[i+1].x - plot->points[i].x)/2.0;
  1003.                         else
  1004.                             dxr = -dxl;
  1005.                     }
  1006.                     else {
  1007.                         dxr = -dxl;
  1008.                     }
  1009.                     if (prev==UNDEFINED)
  1010.                         dxl = -dxr;
  1011.                 }
  1012.                 else {
  1013.                     dxr = boxwidth/2.0;
  1014.                     dxl = -dxr;
  1015.                 }
  1016.             }
  1017.             else {
  1018.                 dxr = plot->points[i].z/2.0;
  1019.                 dxl = -dxr;
  1020.             }
  1021.  
  1022.             dxl= plot->points[i].x+dxl;
  1023.             dxr= plot->points[i].x+dxr;
  1024.             dyt= plot->points[i].y;
  1025.  
  1026.             /* clip to border */
  1027.             if ((y_min < y_max  && dyt < y_min)
  1028.                 || (y_max < y_min  && dyt > y_min))
  1029.                dyt = y_min;
  1030.             if ((y_min < y_max  && dyt > y_max)
  1031.                 || (y_max<y_min  && dyt < y_max))
  1032.                dyt = y_max;
  1033.             if ((x_min < x_max  && dxr < x_min)
  1034.                 || (x_max < x_min  && dxr > x_min))
  1035.                dxr = x_min;
  1036.             if ((x_min < x_max  && dxr > x_max)
  1037.                 || (x_max<x_min  && dxr < x_max))
  1038.                dxr = x_max;
  1039.             if ((x_min < x_max  && dxl < x_min)
  1040.                 || (x_max < x_min  && dxl > x_min))
  1041.                dxl = x_min;
  1042.             if ((x_min < x_max  && dxl > x_max)
  1043.                 || (x_max<x_min  && dxl < x_max))
  1044.                dxl = x_max;
  1045.  
  1046.             xl= map_x(dxl);
  1047.             xr= map_x(dxr);
  1048.             yt = map_y(dyt);
  1049.  
  1050.             (*t->move)(xl,xaxis_y);
  1051.             (*t->vector)(xl,yt);
  1052.             (*t->vector)(xr,yt);
  1053.             (*t->vector)(xr,xaxis_y);
  1054.             (*t->vector)(xl,xaxis_y);
  1055.             break;
  1056.           }
  1057.           default:        /* just a safety */
  1058.           case UNDEFINED: {
  1059.              break;
  1060.           }
  1061.        }
  1062.        prev = plot->points[i].type;
  1063.     }
  1064. }
  1065.  
  1066. /* plot_points:
  1067.  * Plot the curves in POINTSTYLE style
  1068.  */
  1069. void
  1070. plot_points(plot)
  1071.     struct curve_points *plot;
  1072. {
  1073.     int i;
  1074.     int x,y;
  1075.     struct termentry *t = &term_tbl[term];
  1076.  
  1077.     for (i = 0; i < plot->p_count; i++) {
  1078.        if (plot->points[i].type == INRANGE) {
  1079.           x = map_x(plot->points[i].x);
  1080.           y = map_y(plot->points[i].y);
  1081.           /* do clipping if necessary */
  1082.           if (!clip_points ||
  1083.              (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  1084.               && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  1085.             (*t->point)(x,y, plot->point_type);
  1086.        }
  1087.     }
  1088. }
  1089.  
  1090. /* plot_dots:
  1091.  * Plot the curves in DOTS style
  1092.  */
  1093. void
  1094. plot_dots(plot)
  1095.     struct curve_points *plot;
  1096. {
  1097.     int i;
  1098.     int x,y;
  1099.     struct termentry *t = &term_tbl[term];
  1100.  
  1101.     for (i = 0; i < plot->p_count; i++) {
  1102.        if (plot->points[i].type == INRANGE) {
  1103.           x = map_x(plot->points[i].x);
  1104.           y = map_y(plot->points[i].y);
  1105.           /* point type -1 is a dot */
  1106.           (*t->point)(x,y, -1);
  1107.        }
  1108.     }
  1109. }
  1110.  
  1111. /* single edge intersection algorithm */
  1112. /* Given two points, one inside and one outside the plot, return
  1113.  * the point where an edge of the plot intersects the line segment defined 
  1114.  * by the two points.
  1115.  */
  1116. void
  1117. edge_intersect(points, i, ex, ey)
  1118.     struct coordinate GPHUGE *points; /* the points array */
  1119.     int i;                /* line segment from point i-1 to point i */
  1120.     double *ex, *ey;        /* the point where it crosses an edge */
  1121. {
  1122.     /* global x_min, x_max, y_min, x_max */
  1123.     double ax = points[i-1].x;
  1124.     double ay = points[i-1].y;
  1125.     double bx = points[i].x;
  1126.     double by = points[i].y;
  1127.     double x, y;            /* possible intersection point */
  1128.  
  1129.     if (by == ay) {
  1130.        /* horizontal line */
  1131.        /* assume inrange(by, y_min, y_max) */
  1132.        *ey = by;        /* == ay */
  1133.  
  1134.        if (inrange(x_max, ax, bx))
  1135.         *ex = x_max;
  1136.        else if (inrange(x_min, ax, bx))
  1137.         *ex = x_min;
  1138.        else {
  1139.         (*term_tbl[term].text)();
  1140.         (void) fflush(outfile);
  1141.         int_error("error in edge_intersect", NO_CARET);
  1142.        }
  1143.        return;
  1144.     } else if (bx == ax) {
  1145.        /* vertical line */
  1146.        /* assume inrange(bx, x_min, x_max) */
  1147.        *ex = bx;        /* == ax */
  1148.  
  1149.        if (inrange(y_max, ay, by))
  1150.         *ey = y_max;
  1151.        else if (inrange(y_min, ay, by))
  1152.         *ey = y_min;
  1153.        else {
  1154.         (*term_tbl[term].text)();
  1155.         (void) fflush(outfile);
  1156.         int_error("error in edge_intersect", NO_CARET);
  1157.        }
  1158.        return;
  1159.     }
  1160.  
  1161.     /* slanted line of some kind */
  1162.  
  1163.     /* does it intersect y_min edge */
  1164.     if (inrange(y_min, ay, by) && y_min != ay && y_min != by) {
  1165.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1166.        if (inrange(x, x_min, x_max)) {
  1167.           *ex = x;
  1168.           *ey = y_min;
  1169.           return;            /* yes */
  1170.        }
  1171.     }
  1172.     
  1173.     /* does it intersect y_max edge */
  1174.     if (inrange(y_max, ay, by) && y_max != ay && y_max != by) {
  1175.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1176.        if (inrange(x, x_min, x_max)) {
  1177.           *ex = x;
  1178.           *ey = y_max;
  1179.           return;            /* yes */
  1180.        }
  1181.     }
  1182.  
  1183.     /* does it intersect x_min edge */
  1184.     if (inrange(x_min, ax, bx) && x_min != ax && x_min != bx) {
  1185.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1186.        if (inrange(y, y_min, y_max)) {
  1187.           *ex = x_min;
  1188.           *ey = y;
  1189.           return;
  1190.        }
  1191.     }
  1192.  
  1193.     /* does it intersect x_max edge */
  1194.     if (inrange(x_max, ax, bx) && x_max != ax && x_max != bx) {
  1195.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1196.        if (inrange(y, y_min, y_max)) {
  1197.           *ex = x_max;
  1198.           *ey = y;
  1199.           return;
  1200.        }
  1201.     }
  1202.  
  1203.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  1204.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  1205.     * FALSE above. Otherwise we fall through all the tests above. 
  1206.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  1207.     * since either a or b must be INRANGE. 
  1208.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1209.     * Handle them carefully here. As yet we have no way for them to be 
  1210.     * +VERYLARGE.
  1211.     */
  1212.     if (ax == -VERYLARGE) {
  1213.        if (ay != -VERYLARGE) {
  1214.           *ex = min(x_min, x_max);
  1215.           *ey = by;
  1216.           return;
  1217.        }
  1218.     } else if (bx == -VERYLARGE) {
  1219.        if (by != -VERYLARGE) {
  1220.           *ex = min(x_min, x_max);
  1221.           *ey = ay;
  1222.           return;
  1223.        }
  1224.     } else if (ay == -VERYLARGE) {
  1225.        /* note we know ax != -VERYLARGE */
  1226.        *ex = bx;
  1227.        *ey = min(y_min, y_max);
  1228.        return;
  1229.     } else if (by == -VERYLARGE) {
  1230.        /* note we know bx != -VERYLARGE */
  1231.        *ex = ax;
  1232.        *ey = min(y_min, y_max);
  1233.        return;
  1234.     }
  1235.  
  1236.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  1237.     * or the inrange point is on the edge, and
  1238.      * the line segment from the outrange point does not cross any 
  1239.     * other edges to get there. In either case, we return the inrange 
  1240.     * point as the 'edge' intersection point. This will basically draw
  1241.     * line.
  1242.     */
  1243.     if (points[i].type == INRANGE) {
  1244.        *ex = bx; 
  1245.        *ey = by;
  1246.     } else {
  1247.        *ex = ax; 
  1248.        *ey = ay;
  1249.     }
  1250.     return;
  1251. }
  1252.  
  1253. /* XXX - JG  */
  1254. /* single edge intersection algorithm for "steps" curves */
  1255. /* 
  1256.  * Given two points, one inside and one outside the plot, return
  1257.  * the point where an edge of the plot intersects the line segments
  1258.  * forming the step between the two points. 
  1259.  *
  1260.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1261.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1262.  * (x2,y1)->(x2,y2). 
  1263.  */
  1264. void
  1265. edge_intersect_steps(points, i, ex, ey)
  1266.     struct coordinate *points; /* the points array */
  1267.     int i;                /* line segment from point i-1 to point i */
  1268.     double *ex, *ey;        /* the point where it crosses an edge */
  1269. {
  1270.     /* global x_min, x_max, y_min, x_max */
  1271.     double ax = points[i-1].x;
  1272.     double ay = points[i-1].y;
  1273.     double bx = points[i].x;
  1274.     double by = points[i].y;
  1275.  
  1276.     if (points[i].type == INRANGE) {    /* from OUTRANGE to INRANG */
  1277.         if (inrange(ay,y_min,y_max)) {
  1278.         *ey = ay;
  1279.         if (ax > x_max)
  1280.             *ex = x_max;
  1281.         else            /* x < x_min */
  1282.             *ex = x_min;
  1283.         } else {
  1284.             *ex = bx;
  1285.         if (ay > y_max)     
  1286.             *ey = y_max;
  1287.         else            /* y < y_min */
  1288.             *ey = y_min;
  1289.         }
  1290.     } else {                /* from INRANGE to OUTRANGE */
  1291.         if (inrange(bx,x_min,x_max)) {
  1292.         *ex = bx;
  1293.         if (by > y_max)
  1294.             *ey = y_max;
  1295.         else            /* y < y_min */
  1296.             *ey = y_min;
  1297.         } else {
  1298.             *ey = ay;
  1299.         if (bx > x_max)     
  1300.             *ex = x_max;
  1301.         else            /* x < x_min */
  1302.             *ex = x_min;
  1303.         }
  1304.     }
  1305.     return;
  1306. }
  1307.  
  1308. /* XXX - JG  */
  1309. /* double edge intersection algorithm for "steps" plot */
  1310. /* Given two points, both outside the plot, return the points where an 
  1311.  * edge of the plot intersects the line segments forming a step 
  1312.  * by the two points. There may be zero, one, two, or an infinite number
  1313.  * of intersection points. (One means an intersection at a corner, infinite
  1314.  * means overlaying the edge itself). We return FALSE when there is nothing
  1315.  * to draw (zero intersections), and TRUE when there is something to 
  1316.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1317.  * not distinguish it - we draw it anyway).
  1318.  *
  1319.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1320.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1321.  * (x2,y1)->(x2,y2). 
  1322.  */
  1323. TBOOLEAN                /* any intersection? */
  1324. two_edge_intersect_steps(points, i, lx, ly)
  1325.     struct coordinate *points; /* the points array */
  1326.     int i;                /* line segment from point i-1 to point i */
  1327.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1328. {
  1329.     /* global x_min, x_max, y_min, x_max */
  1330.     double ax = points[i-1].x;
  1331.     double ay = points[i-1].y;
  1332.     double bx = points[i].x;
  1333.     double by = points[i].y;
  1334.  
  1335.     if ( max(ax,bx) < x_min || min(ax,bx) > x_max || 
  1336.          max(ay,by) < y_min || min(ay,by) > y_max ||
  1337.          ( (ay  > y_max || ay < y_min)            &&
  1338.            (bx  > x_max || bx < x_min)  ) ) {
  1339.     return(FALSE);                
  1340.     } else if (inrange(ay,y_min,y_max) && inrange(bx,x_min,x_max)) {    /* corner of step inside plotspace */
  1341.         *ly++ = ay;
  1342.     if (ax < x_min) 
  1343.         *lx++ = x_min;
  1344.     else 
  1345.         *lx++ = x_max;
  1346.  
  1347.     *lx++ = bx;
  1348.     if (by < x_min) 
  1349.         *ly++ = y_min;
  1350.     else 
  1351.         *ly++ = y_max;
  1352.  
  1353.     return(TRUE);
  1354.     } else if (inrange(ay,y_min,y_max)) {    /* cross plotspace in x-direction */
  1355.     *lx++ = x_min;
  1356.     *ly++ = ay;
  1357.     *lx++ = x_max;
  1358.     *ly++ = ay;
  1359.     return(TRUE);
  1360.     } else if (inrange(ax,x_min,x_max)) {    /* cross plotspace in y-direction */
  1361.     *lx++ = bx;
  1362.     *ly++ = y_min;
  1363.     *lx++ = bx;
  1364.     *ly++ = y_max;
  1365.     return(TRUE);
  1366.     } else
  1367.     return(FALSE);
  1368. }
  1369.  
  1370. /* double edge intersection algorithm */
  1371. /* Given two points, both outside the plot, return
  1372.  * the points where an edge of the plot intersects the line segment defined 
  1373.  * by the two points. There may be zero, one, two, or an infinite number
  1374.  * of intersection points. (One means an intersection at a corner, infinite
  1375.  * means overlaying the edge itself). We return FALSE when there is nothing
  1376.  * to draw (zero intersections), and TRUE when there is something to 
  1377.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1378.  * not distinguish it - we draw it anyway).
  1379.  */
  1380. TBOOLEAN                /* any intersection? */
  1381. two_edge_intersect(points, i, lx, ly)
  1382.     struct coordinate GPHUGE *points; /* the points array */
  1383.     int i;                /* line segment from point i-1 to point i */
  1384.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1385. {
  1386.     /* global x_min, x_max, y_min, x_max */
  1387.     double ax = points[i-1].x;
  1388.     double ay = points[i-1].y;
  1389.     double bx = points[i].x;
  1390.     double by = points[i].y;
  1391.     double x, y;            /* possible intersection point */
  1392.     TBOOLEAN intersect = FALSE;
  1393.  
  1394.     if (by == ay) {
  1395.        /* horizontal line */
  1396.        /* y coord must be in range, and line must span both x_min and x_max */
  1397.        /* note that spanning x_min implies spanning x_max */
  1398.        if (inrange(by, y_min, y_max) && inrange(x_min, ax, bx)) {
  1399.           *lx++ = x_min;
  1400.           *ly++ = by;
  1401.           *lx++ = x_max;
  1402.           *ly++ = by;
  1403.           return(TRUE);
  1404.        } else
  1405.         return(FALSE);
  1406.     } else if (bx == ax) {
  1407.        /* vertical line */
  1408.        /* x coord must be in range, and line must span both y_min and y_max */
  1409.        /* note that spanning y_min implies spanning y_max */
  1410.        if (inrange(bx, x_min, x_max) && inrange(y_min, ay, by)) {
  1411.           *lx++ = bx;
  1412.           *ly++ = y_min;
  1413.           *lx++ = bx;
  1414.           *ly++ = y_max;
  1415.           return(TRUE);
  1416.        } else
  1417.         return(FALSE);
  1418.     }
  1419.  
  1420.     /* slanted line of some kind */
  1421.     /* there can be only zero or two intersections below */
  1422.  
  1423.     /* does it intersect y_min edge */
  1424.     if (inrange(y_min, ay, by)) {
  1425.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1426.        if (inrange(x, x_min, x_max)) {
  1427.           *lx++ = x;
  1428.           *ly++ = y_min;
  1429.           intersect = TRUE;
  1430.        }
  1431.     }
  1432.     
  1433.     /* does it intersect y_max edge */
  1434.     if (inrange(y_max, ay, by)) {
  1435.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1436.        if (inrange(x, x_min, x_max)) {
  1437.           *lx++ = x;
  1438.           *ly++ = y_max;
  1439.           intersect = TRUE;
  1440.        }
  1441.     }
  1442.  
  1443.     /* does it intersect x_min edge */
  1444.     if (inrange(x_min, ax, bx)) {
  1445.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1446.        if (inrange(y, y_min, y_max)) {
  1447.           *lx++ = x_min;
  1448.           *ly++ = y;
  1449.           intersect = TRUE;
  1450.        }
  1451.     }
  1452.  
  1453.     /* does it intersect x_max edge */
  1454.     if (inrange(x_max, ax, bx)) {
  1455.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1456.        if (inrange(y, y_min, y_max)) {
  1457.           *lx++ = x_max;
  1458.           *ly++ = y;
  1459.           intersect = TRUE;
  1460.        }
  1461.     }
  1462.  
  1463.     if (intersect)
  1464.      return(TRUE);
  1465.  
  1466.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1467.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1468.     * FALSE above.
  1469.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1470.     * Otherwise we fall through all the tests above. 
  1471.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1472.     */
  1473.     if (ax == -VERYLARGE) {
  1474.        if (ay != -VERYLARGE
  1475.           && inrange(by, y_min, y_max) && inrange(x_max, ax, bx)) {
  1476.           *lx++ = x_min;
  1477.           *ly = by;
  1478.           *lx++ = x_max;
  1479.           *ly = by;
  1480.           intersect = TRUE;
  1481.        }
  1482.     } else if (bx == -VERYLARGE) {
  1483.        if (by != -VERYLARGE
  1484.           && inrange(ay, y_min, y_max) && inrange(x_max, ax, bx)) {
  1485.           *lx++ = x_min;
  1486.           *ly = ay;
  1487.           *lx++ = x_max;
  1488.           *ly = ay;
  1489.           intersect = TRUE;
  1490.        }
  1491.     } else if (ay == -VERYLARGE) {
  1492.        /* note we know ax != -VERYLARGE */
  1493.        if (inrange(bx, x_min, x_max) && inrange(y_max, ay, by)) {
  1494.           *lx++ = bx;
  1495.           *ly = y_min;
  1496.           *lx++ = bx;
  1497.           *ly = y_max;
  1498.           intersect = TRUE;
  1499.        }
  1500.     } else if (by == -VERYLARGE) {
  1501.        /* note we know bx != -VERYLARGE */
  1502.        if (inrange(ax, x_min, x_max) && inrange(y_max, ay, by)) {
  1503.           *lx++ = ax;
  1504.           *ly = y_min;
  1505.           *lx++ = ax;
  1506.           *ly = y_max;
  1507.           intersect = TRUE;
  1508.        }
  1509.     }
  1510.  
  1511.     return(intersect);
  1512. }
  1513.  
  1514. /* Polar transform of all curves */
  1515. /* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1516. polar_xform (plots, pcount)
  1517.     struct curve_points *plots;
  1518.     int pcount;            /* count of curves in plots array */
  1519. {
  1520.      struct curve_points *this_plot;
  1521.      int curve;            /* loop var, for curves */
  1522.      register int i, p_cnt;    /* loop/limit var, for points */
  1523.      struct coordinate GPHUGE *pnts;    /* abbrev. for points array */
  1524.     double x, y;            /* new cartesian value */
  1525.     TBOOLEAN anydefined = FALSE;
  1526.     double d2r;
  1527.  
  1528.     if(angles_format == ANGLES_DEGREES){
  1529.         d2r = DEG2RAD;
  1530.     } else {
  1531.         d2r = 1.0;
  1532.     }
  1533.  
  1534. /*
  1535.     Cycle through all the plots converting polar to rectangular.
  1536.      If autoscaling, adjust max and mins. Ignore previous values.
  1537.     If not autoscaling, use the yrange for both x and y ranges.
  1538. */
  1539.     if (autoscale_ly) {
  1540.         x_min = VERYLARGE;
  1541.         y_min = VERYLARGE;
  1542.         x_max = -VERYLARGE;
  1543.         y_max = -VERYLARGE;
  1544.         autoscale_lx = TRUE;
  1545.     } else {
  1546.         x_min = y_min;
  1547.         x_max = y_max;
  1548.     }
  1549.     
  1550.     this_plot = plots;
  1551.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1552.         p_cnt = this_plot->p_count;
  1553.         pnts = &(this_plot->points[0]);
  1554.  
  1555.     /*    Convert to cartesian all points in this curve. */
  1556.         for (i = 0; i < p_cnt; i++) {
  1557.             if (pnts[i].type != UNDEFINED) {
  1558.                  anydefined = TRUE;
  1559.                  /* modify points to reset origin and from degrees */
  1560.                  pnts[i].y -= rmin;
  1561.                  pnts[i].x *= d2r;
  1562.                  /* convert to cartesian coordinates */
  1563.                 x = pnts[i].y*cos(pnts[i].x);
  1564.                 y = pnts[i].y*sin(pnts[i].x);
  1565.                 pnts[i].x = x;
  1566.                 pnts[i].y = y;
  1567.                 if (autoscale_ly) {
  1568.                     if (x_min > x) x_min = x;
  1569.                     if (x_max < x) x_max = x;
  1570.                     if (y_min > y) y_min = y;
  1571.                     if (y_max < y) y_max = y;
  1572.                     pnts[i].type = INRANGE;
  1573.                 } else if(inrange(x, x_min, x_max) && inrange(y, y_min, y_max))
  1574.                   pnts[i].type = INRANGE;
  1575.                 else
  1576.                   pnts[i].type = OUTRANGE;
  1577.             }
  1578.         }    
  1579.     }
  1580.  
  1581.     if (autoscale_lx && anydefined && fabs(x_max - x_min) < zero) {
  1582.         /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1583.         fprintf(stderr, "Warning: empty x range [%g:%g], ", x_min,x_max);
  1584.         if (x_min == 0.0) {
  1585.            x_min = -1; 
  1586.            x_max = 1;
  1587.         } else {
  1588.            x_min *= 0.9;
  1589.            x_max *= 1.1;
  1590.         }
  1591.         fprintf(stderr, "adjusting to [%g:%g]\n", x_min,x_max);
  1592.     }
  1593.     if (autoscale_ly && anydefined && fabs(y_max - y_min) < zero) {
  1594.         /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1595.         fprintf(stderr, "Warning: empty y range [%g:%g], ", y_min, y_max);
  1596.         if (y_min == 0.0) {
  1597.            y_min = -1;
  1598.            y_max = 1;
  1599.         } else {
  1600.            y_min *= 0.9;
  1601.            y_max *= 1.1;
  1602.         }
  1603.         fprintf(stderr, "adjusting to [%g:%g]\n", y_min, y_max);
  1604.     }
  1605. }
  1606.  
  1607. /* DRAW_YTICS: draw a regular tic series, y axis */
  1608. draw_ytics(start, incr, end)
  1609.         double start, incr, end; /* tic series definition */
  1610.         /* assume start < end, incr > 0 */
  1611. {
  1612.     double ticplace;
  1613.     int ltic;            /* for mini log tics */
  1614.     double lticplace;    /* for mini log tics */
  1615.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1616.  
  1617.     if (end == VERYLARGE)            /* for user-def series */
  1618.         end = max(y_min,y_max);
  1619.  
  1620.     /* limit to right side of plot */
  1621.     end = min(end, max(y_min,y_max));
  1622.  
  1623.     /* to allow for rounding errors */
  1624.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1625.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1626.     end = end + SIGNIF*incr; 
  1627.  
  1628.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1629.         if ( inrange(ticplace,ticmin,ticmax) )
  1630.             ytick(ticplace, yformat, incr, 1.0);
  1631.         if (is_log_y && incr == 1.0) {
  1632.             /* add mini-ticks to log scale ticmarks */
  1633.             int lstart, linc;
  1634.             if ((end - start) >= 10)
  1635.             {
  1636.             lstart = 10; /* No little ticks */
  1637.             linc = 5;
  1638.             }
  1639.             else if((end - start) >= 5)
  1640.             {
  1641.             lstart = 2; /* 4 per decade */
  1642.             linc = 3;
  1643.             }
  1644.             else
  1645.             {
  1646.             lstart = 2; /* 9 per decade */
  1647.             linc = 1;
  1648.             }
  1649.             for (ltic = lstart; ltic < (int)base_log_y; ltic += linc) {
  1650.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  1651.                 if ( inrange(lticplace,ticmin,ticmax) )
  1652.                     ytick(lticplace, "\0", incr, 0.5);
  1653.             }
  1654.         }
  1655.     }
  1656. }
  1657.  
  1658. /* DRAW_XTICS: draw a regular tic series, x axis */
  1659. draw_xtics(start, incr, end)
  1660.         double start, incr, end; /* tic series definition */
  1661.         /* assume start < end, incr > 0 */
  1662. {
  1663.     double ticplace;
  1664.     int ltic;            /* for mini log tics */
  1665.     double lticplace;    /* for mini log tics */
  1666.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1667.  
  1668.     if (end == VERYLARGE)            /* for user-def series */
  1669.         end = max(x_min,x_max);
  1670.  
  1671.     /* limit to right side of plot */
  1672.     end = min(end, max(x_min,x_max));
  1673.  
  1674.     /* to allow for rounding errors */
  1675.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1676.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1677.     end = end + SIGNIF*incr; 
  1678.  
  1679.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1680.         if ( inrange(ticplace,ticmin,ticmax) )
  1681.             if(!polar || ticplace == start || ticplace == end) 
  1682.                 xtick(ticplace, xformat, incr, 1.0);
  1683.         if (is_log_x && incr == 1.0) {
  1684.             /* add mini-ticks to log scale ticmarks */
  1685.             int lstart, linc;
  1686.             if ((end - start) >= 10)
  1687.             {
  1688.             lstart = 10; /* No little ticks */
  1689.             linc = 5;
  1690.             }
  1691.             else if((end - start) >= 5)
  1692.             {
  1693.             lstart = 2; /* 4 per decade */
  1694.             linc = 3;
  1695.             }
  1696.             else
  1697.             {
  1698.             lstart = 2; /* 9 per decade */
  1699.             linc = 1;
  1700.             }
  1701.             for (ltic = lstart; ltic < (int)base_log_x; ltic += linc) {
  1702.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  1703.                 if ( inrange(lticplace,ticmin,ticmax) )
  1704.                     xtick(lticplace, "\0", incr, 0.5);
  1705.             }
  1706.         }
  1707.     }
  1708. }
  1709.  
  1710. /* DRAW_SERIES_YTICS: draw a user tic series, y axis */
  1711. draw_series_ytics(start, incr, end)
  1712.         double start, incr, end; /* tic series definition */
  1713.         /* assume start < end, incr > 0 */
  1714. {
  1715.     double ticplace, place;
  1716.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1717.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  1718.  
  1719.     if (end == VERYLARGE)
  1720.         end = max(CheckLog(is_log_y, base_log_y, y_min),
  1721.               CheckLog(is_log_y, base_log_y, y_max));
  1722.     else
  1723.       /* limit to right side of plot */
  1724.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min),
  1725.                  CheckLog(is_log_y, base_log_y, y_max)));
  1726.  
  1727.     /* to allow for rounding errors */
  1728.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1729.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1730.     end = end + SIGNIF*incr; 
  1731.  
  1732.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1733.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  1734.         if ( inrange(place,ticmin,ticmax) )
  1735.          ytick(place, yformat, spacing, 1.0);
  1736.     }
  1737. }
  1738.  
  1739.  
  1740. /* DRAW_SERIES_XTICS: draw a user tic series, x axis */
  1741. draw_series_xtics(start, incr, end)
  1742.         double start, incr, end; /* tic series definition */
  1743.         /* assume start < end, incr > 0 */
  1744. {
  1745.     double ticplace, place;
  1746.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1747.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  1748.  
  1749.     if (end == VERYLARGE)
  1750.         end = max(CheckLog(is_log_x, base_log_x, x_min),
  1751.               CheckLog(is_log_x, base_log_x, x_max));
  1752.     else
  1753.       /* limit to right side of plot */
  1754.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min),
  1755.                  CheckLog(is_log_x, base_log_x, x_max)));
  1756.  
  1757.     /* to allow for rounding errors */
  1758.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1759.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1760.     end = end + SIGNIF*incr; 
  1761.  
  1762.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1763.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  1764.         if ( inrange(place,ticmin,ticmax) )
  1765.          xtick(place, xformat, spacing, 1.0);
  1766.     }
  1767. }
  1768. char GPFAR * GPFAR month[]={
  1769.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  1770. };
  1771. draw_month_ytics()
  1772.     long l_tickplace,l_incr,l_end,m_calc;
  1773.  
  1774.     l_tickplace = (long)y_min;
  1775.     if((double)l_tickplace<y_min)l_tickplace++;
  1776.     l_end=(double)y_max;
  1777.     l_incr=(l_end-l_tickplace+1)/12;
  1778.     if(l_incr<1)l_incr=1;
  1779.     while(l_tickplace<=l_end)
  1780.     {
  1781.     m_calc = (l_tickplace-1)%12;
  1782.     if(m_calc<0)m_calc += 12;
  1783.     ytick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1784.     l_tickplace += l_incr;
  1785.     }
  1786. }
  1787. draw_month_xtics()
  1788. {
  1789.     long l_tickplace,l_incr,l_end,m_calc;
  1790.  
  1791.     l_tickplace = (long)x_min;
  1792.     if((double)l_tickplace<x_min)l_tickplace++;
  1793.     l_end=(double)x_max;
  1794.     l_incr=(l_end-l_tickplace+1)/12;
  1795.     if(l_incr<1)l_incr=1;
  1796.     while(l_tickplace<=l_end)
  1797.     {
  1798.     m_calc = (l_tickplace-1)%12;
  1799.     if(m_calc<0)m_calc += 12;
  1800.     xtick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1801.     l_tickplace += l_incr;
  1802.     }
  1803. }
  1804. char *day[]={
  1805.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  1806. };
  1807. draw_day_ytics()
  1808.     long l_tickplace,l_incr,l_end,m_calc;
  1809.  
  1810.     l_tickplace = (long)y_min;
  1811.     if((double)l_tickplace<y_min)l_tickplace++;
  1812.     l_end=(double)y_max;
  1813.     l_incr=(l_end-l_tickplace+1)/14;
  1814.     if(l_incr<1)l_incr=1;
  1815.     while(l_tickplace<=l_end)
  1816.     {
  1817.     m_calc = l_tickplace%7;
  1818.     if(m_calc<0)m_calc += 7;
  1819.     ytick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1820.     l_tickplace += l_incr;
  1821.     }
  1822. }
  1823. draw_day_xtics()
  1824.     long l_tickplace,l_incr,l_end,m_calc;
  1825.  
  1826.     l_tickplace = (long)x_min;
  1827.     if((double)l_tickplace<x_min)l_tickplace++;
  1828.     l_end=(double)x_max;
  1829.     l_incr=(l_end-l_tickplace+1)/14;
  1830.     if(l_incr<1)l_incr=1;
  1831.     while(l_tickplace<=l_end)
  1832.     {
  1833.     m_calc = l_tickplace%7;
  1834.     if(m_calc<0)m_calc += 7;
  1835.     xtick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1836.     l_tickplace += l_incr;
  1837.     }
  1838. }
  1839. /* DRAW_SET_YTICS: draw a user tic set, y axis */
  1840. draw_set_ytics(list)
  1841.     struct ticmark *list;    /* list of tic marks */
  1842. {
  1843.     double ticplace;
  1844.     double incr = (y_max - y_min) / 10;
  1845.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1846.  
  1847.     while (list != NULL) {
  1848.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  1849.                 : list->position);
  1850.        if ( inrange(ticplace, y_min, y_max)         /* in range */
  1851.           || NearlyEqual(ticplace, y_min, incr)    /* == y_min */
  1852.           || NearlyEqual(ticplace, y_max, incr))    /* == y_max */
  1853.         ytick(ticplace, list->label, incr, 1.0);
  1854.  
  1855.        list = list->next;
  1856.     }
  1857. }
  1858.  
  1859. /* DRAW_SET_XTICS: draw a user tic set, x axis */
  1860. draw_set_xtics(list)
  1861.     struct ticmark *list;    /* list of tic marks */
  1862. {
  1863.     double ticplace;
  1864.     double incr = (x_max - x_min) / 10;
  1865.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1866.  
  1867.     while (list != NULL) {
  1868.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  1869.                 : list->position);
  1870.        if ( inrange(ticplace, x_min, x_max)         /* in range */
  1871.           || NearlyEqual(ticplace, x_min, incr)    /* == x_min */
  1872.           || NearlyEqual(ticplace, x_max, incr))    /* == x_max */
  1873.         xtick(ticplace, list->label, incr, 1.0);
  1874.  
  1875.        list = list->next;
  1876.     }
  1877. }
  1878.  
  1879. /* draw and label a y-axis ticmark */
  1880. ytick(place, text, spacing, ticscale)
  1881.         double place;                   /* where on axis to put it */
  1882.         char *text;                     /* optional text label */
  1883.         double spacing;         /* something to use with checkzero */
  1884.         double ticscale;         /* scale factor for tic mark (0..1] */
  1885. {
  1886.     register struct termentry *t = &term_tbl[term];
  1887.     char ticlabel[101];
  1888.     int ticsize = (int)((t->h_tic) * ticscale);
  1889.  
  1890.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1891.     if (grid) {
  1892.            (*t->linetype)(-1);  /* axis line type */
  1893.            /* do not put a rectangular grid on a polar plot */
  1894.        if( !polar){
  1895.          (*t->move)(xleft, map_y(place));
  1896.          (*t->vector)(xright, map_y(place));
  1897.            } else {   /* put a circular grid for polar -- not clipped! */
  1898.              int i;
  1899.         (*t->move)(map_x(ZERO), map_y(place));
  1900.         for( i=0; i <= 360; i++)
  1901.            (*t->vector)( map_x(place*sin( (double) DEG2RAD*i)),
  1902.             map_y(place*cos( (double) DEG2RAD*i)) );
  1903.         }
  1904.        (*t->linetype)(-2); /* border linetype */
  1905.     }
  1906.     if (tic_in) {
  1907.       /* if polar plot, put the tics along the axes */
  1908.       if( polar){
  1909.            (*t->move)(map_x(ZERO),map_y(place));
  1910.            (*t->vector)(map_x(ZERO) + ticsize, map_y(place));
  1911.            (*t->move)(map_x(ZERO), map_y(place));
  1912.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1913.      } else {
  1914.        (*t->move)(xleft, map_y(place));
  1915.            (*t->vector)(xleft + ticsize, map_y(place));
  1916.            (*t->move)(xright, map_y(place));
  1917.            (*t->vector)(xright - ticsize, map_y(place));
  1918.      }
  1919.     } else {
  1920.       if( polar){
  1921.            (*t->move)(map_x(ZERO), map_y(place));
  1922.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1923.      }else{
  1924.            (*t->move)(xleft, map_y(place));
  1925.            (*t->vector)(xleft - ticsize, map_y(place));
  1926.      }
  1927.     }
  1928.  
  1929.     /* label the ticmark */
  1930.     if (text == NULL) 
  1931.      text = yformat;
  1932.     
  1933.     if( polar){
  1934.       (void) sprintf(ticlabel, text,
  1935.         CheckLog(is_log_y, base_log_y, fabs( place)+rmin));
  1936.       if ((*t->justify_text)(RIGHT)) {
  1937.        (*t->put_text)(map_x(ZERO)-(t->h_char),
  1938.                    map_y(place), ticlabel);
  1939.      } else {
  1940.        (*t->put_text)(map_x(ZERO)-(t->h_char)*(strlen(ticlabel)+1),
  1941.                    map_y(place), ticlabel);
  1942.      }
  1943.     } else {
  1944.     
  1945.       (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  1946.       if ((*t->justify_text)(RIGHT)) {
  1947.        (*t->put_text)(xleft-(t->h_char),
  1948.                    map_y(place), ticlabel);
  1949.      } else {
  1950.        (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1951.                    map_y(place), ticlabel);
  1952.      }
  1953.     }
  1954. }
  1955.  
  1956. /* draw and label an x-axis ticmark */
  1957. xtick(place, text, spacing, ticscale)
  1958.         double place;                   /* where on axis to put it */
  1959.         char *text;                     /* optional text label */
  1960.         double spacing;         /* something to use with checkzero */
  1961.         double ticscale;         /* scale factor for tic mark (0..1] */
  1962. {
  1963.     register struct termentry *t = &term_tbl[term];
  1964.     char ticlabel[101];
  1965.     int ticsize = (int)((t->v_tic) * ticscale);
  1966.  
  1967.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1968.     if (grid) {
  1969.            (*t->linetype)(-1);  /* axis line type */
  1970.            if( !polar){  /* do not place a rectangular grid */
  1971.          (*t->move)(map_x(place), ybot);
  1972.          (*t->vector)(map_x(place), ytop);
  1973.            } else { /* angular lines only for start and stop */
  1974.          int i;
  1975.          for( i=0; i < 360; i+=10){
  1976.          (*t->move)(map_x(ZERO),map_y(ZERO) );
  1977.          (*t->vector)(map_x(-place*cos((double) DEG2RAD*i)),
  1978.              map_y(-place*sin( (double)DEG2RAD*i)));
  1979.          if( i%90 == 0){
  1980.              (void) sprintf(ticlabel, "%d", i);
  1981.          (*t->put_text)(map_x(-1.05*place*cos((double) DEG2RAD*i))
  1982.              +(t->h_char)*strlen(ticlabel)/2,
  1983.              map_y(-1.05*place*sin( (double)DEG2RAD*i))
  1984.                  , ticlabel);
  1985.          }
  1986.          }
  1987.            }
  1988.        (*t->linetype)(-2); /* border linetype */
  1989.     }
  1990.     if (tic_in) {
  1991.       if( polar){
  1992.            (*t->move)(map_x(place), map_y(ZERO));
  1993.            (*t->vector)(map_x(place), map_y(ZERO) + ticsize);
  1994.            (*t->move)(map_x(place), map_y(ZERO));
  1995.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1996.      } else{
  1997.            (*t->move)(map_x(place), ybot);
  1998.            (*t->vector)(map_x(place), ybot + ticsize);
  1999.            (*t->move)(map_x(place), ytop);
  2000.            (*t->vector)(map_x(place), ytop - ticsize);
  2001.      }
  2002.     } else {
  2003.       if( polar){
  2004.            (*t->move)(map_x(place), map_y(ZERO));
  2005.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  2006.      }else{
  2007.            (*t->move)(map_x(place), ybot);
  2008.            (*t->vector)(map_x(place), ybot - ticsize);
  2009.      }
  2010.     }
  2011.     
  2012.     /* label the ticmark */
  2013.     if (text == NULL)
  2014.      text = xformat;
  2015.  
  2016.     if(polar){
  2017.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, fabs(place)+rmin));
  2018.       if ((*t->justify_text)(CENTRE)) {
  2019.        (*t->put_text)(map_x(place),
  2020.                    map_y(ZERO)-(t->v_char), ticlabel);
  2021.      } else {
  2022.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2023.                    map_y(ZERO)-(t->v_char), ticlabel);
  2024.      }
  2025.     }else{
  2026.  
  2027.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2028.       if ((*t->justify_text)(CENTRE)) {
  2029.        (*t->put_text)(map_x(place),
  2030.                    ybot-(t->v_char), ticlabel);
  2031.      } else {
  2032.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2033.                    ybot-(t->v_char), ticlabel);
  2034.      }
  2035.     }
  2036. }
  2037.